package org.apache.solr.search.grouping.distributed.requestfactory;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.ShardRequest;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.grouping.GroupingSpecification;
import org.apache.solr.search.grouping.distributed.ShardRequestFactory;

/**
 * Concrete implementation of {@link ShardRequestFactory} that creates
 * {@link ShardRequest} instances for getting the search groups from all shards.
 */
public class SearchGroupsRequestFactory implements ShardRequestFactory {

	/**
	 * {@inheritDoc}
	 */
	public ShardRequest[] constructRequest(ResponseBuilder rb) {
		ShardRequest sreq = new ShardRequest();
		GroupingSpecification groupingSpecification = rb.getGroupingSpec();
		if (groupingSpecification.getFields().length == 0) {
			return new ShardRequest[0];
		}

		sreq.purpose = ShardRequest.PURPOSE_GET_TOP_GROUPS;

		sreq.params = new ModifiableSolrParams(rb.req.getParams());
		// TODO: base on current params or original params?

		// don't pass through any shards param
		sreq.params.remove(ShardParams.SHARDS);

		// set the start (offset) to 0 for each shard request so we can properly
		// merge
		// results from the start.
		if (rb.shards_start > -1) {
			// if the client set shards.start set this explicitly
			sreq.params.set(CommonParams.START, rb.shards_start);
		} else {
			sreq.params.set(CommonParams.START, "0");
		}
		// TODO: should we even use the SortSpec? That's obtained from the
		// QParser, and
		// perhaps we shouldn't attempt to parse the query at this level?
		// Alternate Idea: instead of specifying all these things at the upper
		// level,
		// we could just specify that this is a shard request.
		if (rb.shards_rows > -1) {
			// if the client set shards.rows set this explicity
			sreq.params.set(CommonParams.ROWS, rb.shards_rows);
		} else {
			sreq.params.set(CommonParams.ROWS, rb.getSortSpec().getOffset()
					+ rb.getSortSpec().getCount());
		}

		// in this first phase, request only the unique key field
		// and any fields needed for merging.
		sreq.params.set("group.distibuted.first", "true");

		if ((rb.getFieldFlags() & SolrIndexSearcher.GET_SCORES) != 0
				|| rb.getSortSpec().includesScore()) {
			sreq.params.set(CommonParams.FL, rb.req.getSchema()
					.getUniqueKeyField().getName()
					+ ",score");
		} else {
			sreq.params.set(CommonParams.FL, rb.req.getSchema()
					.getUniqueKeyField().getName());
		}
		return new ShardRequest[] { sreq };
	}

}
